<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>风险域名管理</title>

        <style>
            * {
            padding: 0;
            margin: 0;
            list-style: none;
            }

            #header {
            padding: 15px;
            background-color: #eeeeee;
            transition: .2s;
            position: sticky;
            z-index: 999;
            }

            #header .header-content {
            display: flex;
            flex-wrap: wrap;
            }

            #header .header-content li {
            margin: 3px;
            font-size: 14px;
            vertical-align: middle;
            }

            #header .header-content li span {
            vertical-align: middle;
            }

            #header select, #header input {
            padding: 2px 4px;
            outline: none;
            }

            #header button {
            box-sizing: border-box;
            padding: 2px 15px;
            border: none;
            background-color: #fff;
            border: 1px solid #ccc;
            cursor: pointer;
            }

            #header button:hover {
            opacity: .7;
            border-color: #e6e6e6;
            }

            #content {
            padding: 15px;
            box-sizing: border-box;
            overflow: auto;
            }

            #content #tableCenter {
            width: 100%;
            border-collapse: collapse;
            font-size: 12px;
            }

            #content #tableCenter thead tr {
            color: #95aa6d;
            font-weight: bold;
            position: sticky;
            top: -15px;
            }

            #content #tableCenter thead tr th {
            white-space: nowrap;
            padding: 5px 10px;
            font-size: 16px;
            }

            #content #tableCenter tbody tr.active {
            background-color: yellow !important;
            }

            #content #tableCenter tbody td {
            padding: 12px 10px;
            color: #006d36;
            }

            #content #tableCenter tbody td .actions {
            display: flex;
            align-items: center;
            flex-direction: column;
            }

            #content #tableCenter tbody td .actions button {
            width: 80%;
            }

            #content #tableCenter td, #content #tableCenter th {
            text-align: center;
            }

            #content #tableCenter tr:nth-child(even) {
            background: #e6eed6;
            }

            #content #tableCenter tr:nth-child(odd) {
            background: white;
            }

            #content .site_img {
            transition: .2s;
            }

            #content .site_img:hover {
            transform: scale(4);
            }

            .modalbox {
            max-width: 600px;
            width: 0px;
            box-sizing: content-box;
            overflow: hidden;
            position: fixed;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.3);
            z-index: 888;
            background-color: #fff;
            }

            .modalbox #modalbox-title {
            text-align: center;
            font-weight: bold;
            }

            .modalbox #modalbox-content {
            min-height: 100px;
            max-height: 500px;
            overflow-y: auto;
            margin: 10px 0px;
            border-bottom: 1px solid #ccc;
            text-align: center;
            box-sizing: border-box;
            }

            .modalbox #modalbox-content > ul > li {
            margin-bottom: 10px;
            }

            .modalbox #modalbox-content select, .modalbox #modalbox-content input[type=text] {
            width: 80%;
            padding: 10px;
            border-radius: 5px;
            border: 1px solid #ccc;
            box-sizing: border-box;
            }

            .modalbox #modalbox-content select:focus, .modalbox #modalbox-content input[type=text]:focus {
            outline: none;
            border: 1px solid #8a8a8a;
            }

            .modalbox #modalbox-control {
            display: flex;
            justify-content: center;
            }

            .modalbox #modalbox-control .control {
            width: 80%;
            text-align: right;
            }

            .modalbox #modalbox-control button {
            padding: 5px 20px;
            outline: none;
            cursor: pointer;
            margin: 0px 3px;
            border: none;
            border-radius: 15px;
            color: #fff;
            font-size: 15px;
            box-sizing: border-box;
            }

            .modalbox #modalbox-control button:nth-child(1) {
            background-color: #039703;
            }

            .modalbox #modalbox-control button:nth-child(2) {
            background-color: #a70000;
            }

            .modalbox #modalbox-control button:hover {
            opacity: .7;
            }

            .modalbox .actions label {
            margin-right: 5px;
            }

            .modalbox .actions label > input {
            vertical-align: middle;
            margin-right: 3px;
            }

            .modalbox.show {
            animation: showBoxan .5s forwards;
            }

            .modalbox.hide {
            animation: hideBoxan .5s forwards;
            }

            #globalMsg {
            position: fixed;
            top: 25%;
            left: 50%;
            transform: translateX(-50%);
            z-index: 9999;
            animation: move .5s forwards;
            }

            #globalMsg .tips {
            background-color: #fff;
            border-radius: 10px;
            padding: 5px 15px;
            letter-spacing: 3px;
            font-weight: bold;
            box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.3);
            }

            #globalConfirm {
            position: fixed;
            top: 25%;
            left: 50%;
            transform: translateX(-50%);
            z-index: 9999;
            animation: move .5s forwards;
            box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.3);
            padding: 10px;
            z-index: 9999;
            background-color: #fff;
            }

            #globalConfirm .container {
            min-width: 300px;
            }

            #globalConfirm .container .title {
            padding-bottom: 15px;
            margin-bottom: 15px;
            text-align: center;
            border-bottom: 1px solid #ccc;
            }

            #globalConfirm .container .control {
            display: flex;
            justify-content: space-around;
            }

            #globalConfirm .container .control button {
            border: none;
            padding: 8px 20px;
            cursor: pointer;
            }

            #globalConfirm .container .control button:hover {
            opacity: .7;
            }

            #globalConfirm .container .control button:nth-child(2) {
            background-color: #740f0f;
            color: #fff;
            }

            @keyframes move {
            to {
                top: 30%;
            }
            }

            @keyframes showBoxan {
            to {
                width: 80%;
                padding: 15px;
            }
            }

            @keyframes hideBoxan {
            to {
                transform: scale(0);
                opacity: 0;
                width: 0;
                padding: 0;
            }
            }

    </style>
    </head>
    <body>
        <div id="app">
            <div id="container">
                <div ref="headerCom" id="header">
                    <ul class="header-content">
                        <li>
                            <select v-model="query.white_black_state">
                                <option value>全部</option>
                                <option value="-2">黑</option>
                                <option value="-1">风险</option>
                                <option value="1">未知</option>
                                <option value="2">正常</option>
                                <option value="3">白</option>
                            </select>
                        </li>
                        <li>
                            <select v-model="query.page_size">
                                <option value="20">显示20条</option>
                                <option value="100">显示100条</option>
                                <option value="1000">显示1000条</option>
                            </select>
                        </li>
                        <li><span>合计:<b
                                    style="color: rgb(187, 0, 0);margin: 0px 4px;">{{
                                    count }}</b>条</li>
                            <li><input @keyup.enter="search" placeholder="域名"
                                    v-model="query.domain_name"></li>
                            <li><input @keyup.enter="search" placeholder="链接"
                                    v-model="query.example_urls"></li>
                            <li><input @keyup.enter="search" placeholder="IP"
                                    v-model="query.domain_ips"></li>
                            <li><input @keyup.enter="search" placeholder="备案号"
                                    v-model="query.domain_icp"></li>
                            <li><input @keyup.enter="search" placeholder="主体"
                                    v-model="query.domain_org"></li>
                            <li><input @keyup.enter="search" placeholder="网站图片"
                                    v-model="query.site_imgs"></li>

                            <li>
                                <select v-model="query.port_check">
                                    <option value>端口</option>
                                    <option value="-1">-</option>
                                    <option value="1">√</option>
                                    <option value="2">×</option>
                                </select>
                            </li>
                            <li>
                                <select v-model="query.abroad_check">
                                    <option value>境外</option>
                                    <option value="-1">-</option>
                                    <option value="1">√</option>
                                    <option value="2">×</option>
                                </select>
                            </li>
                            <li>
                                <select v-model="query.tx_check">
                                    <option value>TX</option>
                                    <option value="-1">-</option>
                                    <option value="1">√</option>
                                    <option value="2">×</option>
                                </select>
                            </li>
                            <li>
                                <select v-model="query.pic_check">
                                    <option value>图像</option>
                                    <option value="-1">-</option>
                                    <option value="1">√</option>
                                    <option value="2">×</option>
                                </select>
                            </li>
                            <li>
                                <select v-model="query.caution">
                                    <option value>留观</option>
                                    <option value="-1">否</option>
                                    <option value="1">是</option>
                                </select>
                            </li>
                            <li>
                                <button
                                    style="background-color: rgb(0, 0, 110);color: #fff;"
                                    @click="search">搜索</button>
                            </li>
                            <li>
                                <button @click="showModal = true">添加域名</button>
                            </li>
                            <li>
                                <button @click="actionModalShow = true"
                                    :disabled="chooseList.length == 0"
                                    :style="{backgroundColor :  chooseList.length > 0 ? 'rgb(0, 75, 136)' : '#ccc' }"
                                    style="color: white;">批量操作</button>
                            </li>
                        </ul>
                    </div>
                    <div id="content">
                        <table id="tableCenter" cell>
                            <thead>
                                <tr>
                                    <th></th>
                                    <th>ID</th>
                                    <th>域名</th>
                                    <th>链接</th>
                                    <th>分类</th>
                                    <th>常驻</th>
                                    <th>IP</th>
                                    <th>备案</th>
                                    <th>主体</th>
                                    <th>网站图片</th>
                                    <th>端口</th>
                                    <th>境外</th>
                                    <th>TX</th>
                                    <th>图像</th>
                                    <th>拦截原因</th>
                                    <th>留观</th>
                                    <th>留观时间</th>
                                    <th>手动添加</th>
                                    <th>创建时间</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr
                                    :class="chooseList.length > 0 && chooseList.filter(t => t.id === item.id).length > 0 ? 'active' : '' "
                                    v-for="item in list" :key="item.id">
                                    <td><input v-if="item.delete_state != 1"
                                            v-on:change="setList(item)"
                                            v-model="item.checked"
                                            type="checkbox"></td>
                                    <td
                                        @click="item.checked = !item.checked;setList(item)">{{item.id}}</td>
                                    <td
                                        @click="item.checked = !item.checked;setList(item)">{{item.domain_name}}</td>
                                    <td style="max-width: 200px;">
                                        <div style="
                                    width: 100%;
                                    word-wrap: break-word;
                                    text-overflow: ellipsis;
                                    display: -webkit-box;
                                    -webkit-box-orient: vertical;
                                    -webkit-line-clamp: 2;
                                    overflow: hidden;
                                ">
                                            <a v-for="url in item.exampleUrls"
                                                :alt="url" :href="url"
                                                target="_blank"
                                                referrerpolicy="no-referrer">{{
                                                url }}</a>
                                        </div>
                                    </td>
                                    <td
                                        :style="whiteBlackStyle(item.white_black_state)">{{whiteBlackState(item.white_black_state)}}</td>
                                    <td>{{boolState(item.persistent_in_client)}}</td>
                                    <td><pre>{{item.domain_ips?JSON.parse(item.domain_ips).map(x=>x.ip+x.loc).join('\n'):''}}</pre></td>
                                    <td>{{item.domain_icp}}</td>
                                    <td>{{item.domain_org}}</td>
                                    <td>
                                        <img class="site_img"
                                            referrerpolicy="no-referrer"
                                            width="50" height="50"
                                            v-if="item.siteImgs && item.siteImgs.length"
                                            :src="item.siteImgs[item.siteImgsPos]"
                                            @click="item.siteImgsPos=(++item.siteImgsPos)%item.siteImgs.length"
                                            :title="item.siteImgs[item.siteImgsPos]">
                                    </td>
                                    <td>{{checkState(item.port_check)}}</td>
                                    <td>{{checkState(item.abroad_check)}}</td>
                                    <td>{{checkState(item.tx_check)}}</td>
                                    <td>{{checkState(item.pic_check)}}</td>
                                    <td>{{item.block_reason}}</td>
                                    <td>{{boolState(item.caution)}}</td>
                                    <td>{{timeTrim(item.caution_time)}}</td>
                                    <td>{{boolState(item.manual_add)}}</td>
                                    <td style="white-space: nowrap"
                                        :title="'更新时间'+timeTrim(item.modify_time)">{{timeTrim(item.create_time)}}</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>

                <div class="modalbox" v-if="showModal"
                    :class="showModal ? 'show' : 'hide'">
                    <div id="modalbox-title">添加域名</div>
                    <div id="modalbox-content">
                        <ul>
                            <li><input v-model="site" type="text"
                                    placeholder="域名地址"></li>
                            <li>
                                <select v-model="domain_State">
                                    <option value="-2">进黑</option>
                                    <option value="-1">进风险</option>
                                    <option value="2">进正常</option>
                                    <option value="3">进白</option>
                                </select>
                            </li>
                        </ul>
                    </div>
                    <div id="modalbox-control">
                        <div class="control">
                            <button v-on:click="handlerModalConfirm('add')">确定</button>
                            <button v-on:click="handlerModalCancel">取消</button>
                        </div>
                    </div>
                </div>

                <div class="modalbox"
                    v-if="chooseList.length > 0 && actionModalShow"
                    :class="actionModalShow ? 'show' : 'hide'">
                    <div id="modalbox-title">操作</div>
                    <div id="modalbox-content">
                        <ul style="text-align: left;">
                            <li>
                                <p>操作域名列表: </p>
                                <ul v-for="item in chooseList" :key="item.id">
                                    <li>{{ item.domain_name }}</li>
                                </ul>
                            </li>
                        </ul>
                    </div>
                    <div class="actions">
                        <label>
                            <input v-model="actionType" name="actionType"
                                value="0" type="radio">
                            <span>删除</span>
                        </label>
                        <label>
                            <input v-model="actionType" name="actionType"
                                value="-2" type="radio">
                            <span>黑</span>
                        </label>
                        <label>
                            <input v-model="actionType" name="actionType"
                                value="-1" type="radio">
                            <span>风险</span>
                        </label>
                        <label>
                            <input v-model="actionType" name="actionType"
                                value="2" type="radio">
                            <span>正常</span>
                        </label>
                        <label>
                            <input v-model="actionType" name="actionType"
                                value="3" type="radio">
                            <span>白</span>
                        </label>
                    </div>
                    <div id="modalbox-control">
                        <div class="control">
                            <button v-on:click="handlerModalConfirm('edit')">确定</button>
                            <button v-on:click="handlerModalCancel">取消</button>
                        </div>
                    </div>
                </div>

                <div id="globalConfirm" v-if="globalConfirmShow">
                    <div class="container">
                        <div class="title">{{ globalConfirmMsg }}</div>
                        <div class="control">
                            <button v-on:click="handlerCancel">取消</button>
                            <button v-on:click="handlerConfirm">确定</button>
                        </div>
                    </div>
                </div>

                <div id="globalMsg" v-if='globalMsg != "" '>
                    <div class="tips">{{ globalMsg }}</div>
                </div>
            </div>
        </body>

    </html>
    <script
        src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.3.6/vue.global.prod.min.js"
        integrity="sha512-jdvIV8HKyuo/emBQ2uZRiCaVRyxoZV7qRIffc6BSLgSVPwFvf3WL0RikITxGwuzJ3kGxiiCKB44Nz8YPdqnOSA=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script>
    const { createApp,ref,onMounted} = Vue

    createApp({
        setup() {
            const scrollToTop = (e) => {
                var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
                if(headerCom.value){
                    if(scrollTop == 0){
                        headerCom.value.removeAttribute('style')
                    }
                    else{
                        headerCom.value.setAttribute('style',`transform:translateY(${scrollTop}px);transition:.2s`)
                    }
                }
            }
            onMounted(()=>{
                window.addEventListener('scroll', scrollToTop,false)
            })
            const query = ref({
                page_size: '20',
                white_black_state: '',
                domain_name: '',
                example_urls: '',
                domain_ips: '',
                domain_icp: '',
                domain_org: '',
                site_imgs: '',
                port_check: '',
                abroad_check: '',
                tx_check: '',
                pic_check: '',
                caution: ''
            })
            const list = ref([])
            const count = ref(0)
            const domain_State = ref(-2)
            const site = ref('')

            const apiPrefix = 'http://192.168.1.55:8080'
            const search = () => {
                const q = [];
                for (const k in query.value) {
                    query.value[k] && q.push(k+'='+query.value[k]);
                }
                list.value = [];
                fetch(apiPrefix + '/admin/domain/list?'+q.join('&')).then(x=>x.json()).then(res=>{
                    res.list.forEach(
                        data => {
                            if (data.example_urls){
                                data.exampleUrls = data.example_urls.split("\n")

                            }

                            if (data.site_imgs){
                                data.siteImgs = data.site_imgs.split("\n");
                                var pos = data.siteImgs.findIndex(x=>x.includes('#score='))
                                if(pos === -1){
                                    pos = 0
                                }
                                data.siteImgsPos = pos;
                            }
                            data.checked = false;
                        }
                    )
                    list.value = res.list;
                    count.value = res.count;
                });
            }
            search();

            const whiteBlackStyle = state => {
                switch (state) {
                    case -2:
                        return 'color:red';
                    case -1:
                        return 'color:orange';
                }
                return ''
            }


        

            const whiteBlackState = state => {
                switch (state) {
                    case -2:
                        return '黑';
                    case -1:
                        return '风险';
                    case 1:
                        return '未知'
                    case 2:
                        return '正常'
                    case 3:
                        return '白'
                    default:
                        return state
                }
            };

            const boolState = state => {
                switch (state) {
                    case -1:
                        return '×'
                    case 1:
                        return '√'
                    default:
                        return state
                }
            };
            const checkState = state => {
                switch (state) {
                    case -1:
                        return '-'
                    case 1:
                        return '√'
                    case 2:
                        return '×'
                    default:
                        return state
                }
            }

            const timeTrim = t =>{
                return t?t.replace(/[TZ]/g, ' ').replace('+08:00',''):''
            }
            const del = item => {
                fetch(apiPrefix + '/admin/domain/del?domainName='+item.domain_name, {method:'post'}).then(r=>r.json()).then(r=>{
                    if(r.err){
                        return alert(r.err)
                    }
                    item.delete_state = 1
                    search()
                })
            }

            const change = (item, newState) => {
                fetch(apiPrefix + '/admin/domain/change?domainName='+item.domain_name + '&tp='+newState, {method:'post'}).then(r=>r.json()).then(r=>{
                    if(r.err){
                        return alert(r.err)
                    }
                    search()
                })
            }

            const add = (tp) => {
                fetch(apiPrefix + '/admin/domain/add?site=' + encodeURIComponent(site.value) + '&tp='+tp, {method:'post'}).then(r=>r.json()).then(r=>{
                    if(r.err){
                        return alert(r.err)
                    }
                    site.value='';
                    search()
                })
            }
            
            const headerCom = ref(null)

            const showModal = ref(false)

            const handlerModalCancel = () => {
                showModal.value = false;
                actionModalShow.value = false;
                domain_State.value = -2;
                site.value = ""
            }
            const handlerModalConfirm = (type) => {
                switch(type){
                    case 'add':
                        if(site.value == ""){
                            showGlobalMsg('域名地址不能为空')
                            return;
                        }
                        add(domain_State.value);
                        showModal.value = false;
                        domain_State.value = -2;

                    break;
                    case 'edit':
                        console.log(actionType.value)
                        if(actionType.value == 0){
                            globalConfirmMsg.value = '确认删除吗?'
                        }
                        else{
                            globalConfirmMsg.value = '确认操作吗?'
                        }
                        globalConfirmShow.value = true;
                    break;
                    default:
                    break;
                }
            }
            const chooseList = ref([])
            const setList = (item) => {
                if(item.checked){
                    chooseList.value.push(item)
                }
                else{
                    const isIndex =  chooseList.value.findIndex(t => item.id == t.id)
                    if(isIndex != -1){
                        chooseList.value.splice(isIndex,1)
                    }
                }
            }

            const globalMsg = ref('')

            
            const showGlobalMsg = (msg) => {
                globalMsg.value = msg;
                setTimeout(() => {
                    globalMsg.value = ""
                }, 2000);
            }
            const handlerCancel = () => {
                globalConfirmShow.value = false;
            }
            const handlerConfirm = () => {
                switch(actionType.value){
                    case 0:
                        chooseList.value.forEach(item=>{
                            del(item)
                        })
                    break;
                    default:
                        chooseList.value.forEach(item=>{
                            change(item,actionType.value)
                        })
                    break;
                }
                globalConfirmShow.value = false;
                actionModalShow.value = false;
                chooseList.value = []

            }
            const globalConfirmShow = ref(false)

            const actionType = ref(0)
            const actionModalShow = ref(false)
            const globalConfirmMsg = ref('确认删除吗')
            return {
                query,
                count,
                site,
                list,
                search,
                whiteBlackStyle,
                whiteBlackState,
                boolState,
                checkState,
                timeTrim,
                del,
                change,
                add,
                domain_State,
                chooseList,
                setList,
                actionType,
                showModal,
                headerCom,
                handlerModalCancel,
                handlerModalConfirm,
                handlerCancel,
                handlerConfirm,
                globalConfirmMsg,
                globalConfirmShow,
                actionModalShow,
                globalMsg,
            }
        }
    }).mount('#app')

    const oDom = {
        APP : document.getElementById('app'),
        HEADER : document.getElementById('header'),
        CONTENT : document.getElementById('content'),
    }


    function init(){
        let { height } = oDom.HEADER.getBoundingClientRect();
        oDom.CONTENT.style.height = window.innerHeight - height + 'px'
    }
    init()

    window.onresize = () => {
        init()
    }
</script>